/*******************************************************************************
 * Copyright (c) 2010 Marcelo Cataldo, Sangeeth Nambiar
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * DepsXMLParser.java
 * 
 * This is an extension of a SAX XML parser to process XML files that
 * contain dependency information. The file format is the following
 * 
 * <nodes>
 * <nodeset type="XXX" name="XXX">
 * <node id="XXX">
 * <properties>
 * <property name="XXX" type="double" value="1.0"/>
 * ...
 * </properties>
 * </node>
 * ...
 * </nodeset>
 * ...
 * </nodes>
 * <networks>
 * <graph sourceType="XXX" targetType="XXX" id="XXX" color="RRR,GGG,BBB">
 * <edge source="COMP001" target="COMP002" value="10.0">
 * </edge>
 * ...
 * </graph>
 * ...
 * </networks>
 * 
 * Contributors:
 *    Marcelo Cataldo  - initial implementation 
 *    Sangeeth Nambiar - initial implementation
 *******************************************************************************/
package edu.cmu.isr.dinvenio.fileParsers;

import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;

import edu.cmu.isr.dinvenio.exceptions.ObjectNotFoundException;
import edu.cmu.isr.dinvenio.model.DepsGraph;

public class DepsXMLParser extends DefaultHandler {

	/*  
     * Set of variables to identify the different
     * sections of the dependency XML file being processed
     */
	private boolean validDepMatrix = false;	
    private boolean inNodeDefs = false;
	private boolean inNodeset = false;
	private String nodeSetName = null;
	private String nodeSetType = null; 
	private String node = null;
    
	private boolean inNetDefs = false;
	private String graphID = null;
	private String graphSName= null;
	private String graphDName = null;
	private boolean inEdge = false;

	private boolean inProps = false;
	private String property = null;
	
	private DepsGraph graph = null;
	
    /* 
     * Constructor 
     */
    public DepsXMLParser (DepsGraph g) 
	{
    	super();
    	this.graph = g;
    }
    
    /* 
     * startElement is called whenever a tag starts 
     */
	public void startElement (
    		String uri, 
    		String name,
    		String qName, 
    		Attributes attrs) 
	{
		if ("".equals(uri)) {
		  if (qName.equals("node")) {
			  if (!inNodeDefs) { 
				  System.out.println("DepsXMLParser.startElement(01): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (!inNodeset) { 
				  System.out.println("DepsXMLParser.startElement(02): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  // process the attributes of the node
			  if (attrs.getLength() == 1 && attrs.getQName(0).equals("id")) {
				  node = attrs.getValue(0);
				  try {
					  graph.addNode(node,nodeSetName);
				  }
				  catch (ObjectNotFoundException e) {
					  e.printStackTrace();
				  }
			  }
			  else {
				  System.out.println("DepsXMLParser.startElement(02): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
		  }
		  else if (qName.equals("edge")) {
			  if (!inNetDefs) { 
				  System.out.println("DepsXMLParser.startElement(03): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (graphID == null) { 
				  System.out.println("DepsXMLParser.startElement(04): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  // process the attributes of the edge
			  inEdge = true;
			  if (attrs.getLength() == 3 && 
					  attrs.getQName(0).equals("source") &&
					  attrs.getQName(1).equals("target") &&
					  attrs.getQName(2).equals("value")) {
				  try {
//					  graph.addEdge(graphID,
//						  DepsGraphNode.generateKey(graphSName,attrs.getValue(0)),
//						  DepsGraphNode.generateKey(graphDName,attrs.getValue(1)),
//						  Double.parseDouble(attrs.getValue(2)));
					  graph.addEdge(graphID,attrs.getValue(0),attrs.getValue(1),Double.parseDouble(attrs.getValue(2)));
				  }
				  catch (ObjectNotFoundException e) {
					  e.printStackTrace();
				  }
			  }
			  else {
				  System.out.println("DepsXMLParser.startElement(02): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
		  }
		  else if (qName.equals("property")) {
			  if (node == null || inEdge) { 
				  System.out.println("DepsXMLParser.startElement(05): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (property != null) { 
				  System.out.println("DepsXMLParser.startElement(05): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  // process attributes of the property definition
			  if (attrs.getLength() == 3 && 
					  attrs.getQName(0).equals("name") &&
					  attrs.getQName(1).equals("type") &&
					  attrs.getQName(2).equals("value")) {
//				  graph.addNodeProperty(
//						  DepsGraphNode.generateKey(nodeSetName,node),
//						  attrs.getValue(0),attrs.getValue(1),attrs.getValue(2));
				  graph.addNodeProperty(nodeSetName,node, attrs.getValue(0),attrs.getValue(1),attrs.getValue(2));
				  property = attrs.getValue(0);
			  }
			  else {
				  System.out.println("DepsXMLParser.startElement(02): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
		  }
		  else if (qName.equals("properties")) {
			  if (node == null || inEdge) { 
				  System.out.println("DepsXMLParser.startElement(06): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  // do something with properties
			  inProps = true;
		  }
		  else if (qName.equals("nodes")) {
			  if (inNodeDefs) { 
				  System.out.println("DepsXMLParser.startElement(07): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (inNetDefs) {
				  System.out.println("DepsXMLParser.startElement(08): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  inNodeDefs = true;
		  }
		  else if (qName.equals("nodeset")) {
			  if (!inNodeDefs) { 
				  System.out.println("DepsXMLParser.startElement(09): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (attrs.getQName(0).equals("type") && attrs.getQName(1).equals("name")) {
				  this.nodeSetType = attrs.getValue(0);
				  this.nodeSetName = attrs.getValue(1);
			  }
			  else if (attrs.getQName(0).equals("name") && attrs.getQName(1).equals("type")) {
				  this.nodeSetName = attrs.getValue(0);
				  this.nodeSetType = attrs.getValue(1);
			  }
			  if (this.nodeSetType == null || this.nodeSetName == null) {
				  System.out.println("DepsXMLParser.startElement(09a): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  inNodeset = true;
			  graph.addNodeSet(nodeSetType, nodeSetName);
		  }
		  else if (qName.equals("networks")) {
			  if (inNodeDefs) { 
				  System.out.println("DepsXMLParser.startElement(10): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (inNetDefs) {
				  System.out.println("DepsXMLParser.startElement(11): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  inNetDefs = true;
		  }
		  else if (qName.equals("graph")) {
			  if (!inNetDefs) { 
				  System.out.println("DepsXMLParser.startElement(12): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  if (attrs.getLength() == 4 && 
					  attrs.getQName(0).equals("sourceType") &&
					  attrs.getQName(1).equals("targetType") &&
					  attrs.getQName(2).equals("id") &&
					  attrs.getQName(3).equals("color")) {
				  graphSName = attrs.getValue(0);
				  graphDName = attrs.getValue(1);
				  graphID = attrs.getValue(2);
				  try {
					  graph.addLayer(graphID,graphSName,graphDName,attrs.getValue(3));
				  }
				  catch (ObjectNotFoundException e) {
					  e.printStackTrace();
				  }
			  }
			  else {
				  System.out.println("DepsXMLParser.startElement(02): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }

		  }
		  else if (qName.equals("DepMatrix")) {
			  if (validDepMatrix) { 
				  System.out.println("DepsXMLParser.startElement(13): INVALID XML FORMAT (" + qName + ")");
				  return;
			  }
			  validDepMatrix = true;
		  }
		  else {
			  System.out.println("DepsXMLParser.startElement(98): INVALID XML FORMAT (" + qName + ")");
			  return;			  
		  }
		  //System.out.println("DEBUG DepsXMLParser.startElement: " + qName);
		  return;
		}

		// done
		System.out.println("DepsXMLParser.startElement(99): INVALID DEPENDENCY XML FORMAT (" + qName + ")");
	}

    /* 
     * endElement is called whenever a tag ends 
     */
    public void endElement (
    		String uri, 
    		String name, 
    		String qName) 
    {
		if ("".equals(uri)) {
			if (qName.equals("node")) {
				if (node == null) { 
					System.out.println("DepsXMLParser.endElement(01): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				node = null;
			}
			else if (qName.equals("edge")) {
				if (!inEdge) { 
					System.out.println("DepsXMLParser.endElement(02): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				inEdge = false;
			}
			else if (qName.equals("property")) {
				if (property ==  null) { 
					System.out.println("DepsXMLParser.endElement(04): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				property = null;
			}
			else if (qName.equals("properties")) {
				if (!inProps) { 
					System.out.println("DepsXMLParser.endElement(03): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				inProps = false;
			}
			else if (qName.equals("nodes")) {
				if (!inNodeDefs) { 
					System.out.println("DepsXMLParser.endElement(05): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				if (inNodeset) { 
					System.out.println("DepsXMLParser.endElement(06): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				inNodeDefs = false;
			}
			else if (qName.equals("nodeset")) {
				if (!inNodeDefs || !inNodeset) { 
					System.out.println("DepsXMLParser.endElement(07): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				inNodeset = false;
				nodeSetName = null;
				nodeSetType = null;
			}
			else if (qName.equals("networks")) {
				if (!inNetDefs) { 
					System.out.println("DepsXMLParser.endElement(08): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				if (graphID != null) {
					System.out.println("DepsXMLParser.endElement(09): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				inNetDefs = false;
			}
			else if (qName.equals("graph")) {
				if (!inNetDefs || graphID == null) { 
					System.out.println("DepsXMLParser.endElement(09): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				graphID = null;
				graphSName = null;
				graphDName = null;
			}
			else if (qName.equals("DepMatrix")) {
				if (!validDepMatrix) { 
					System.out.println("DepsXMLParser.endElement(10): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				if (inNodeDefs || inNetDefs) {
					System.out.println("DepsXMLParser.endElement(11): INVALID XML FORMAT (" + qName + ")");
					return;
				}
				validDepMatrix = false;
    		}	
			else {
				System.out.println("DepsXMLParser.endElement(98): INVALID XML FORMAT (" + qName + ")");
				return;			  
			}
			//System.out.println("DEBUG DepsXMLParser.endElement: " + qName);
			return;
		}

		// done
		System.out.println("DepsXMLParser.endElement: INVALID DEPENDENCY XML FORMAT (" + qName + ")");
    }

    public void characters (
    		char ch[], 
    		int start, 
    		int length)
    {
    	//System.out.print("DEBUG DepsXMLParser.characters:");
    }
}
